package net.neptech.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.neptech.enums.workflow.ApproveAttachmentTypeEnum;
import net.neptech.enums.workflow.ApproveDescTypeEnum;
import net.neptech.enums.workflow.InstanceConstant;
import net.neptech.enums.workflow.TaskTypeEnum;
import net.neptech.model.dto.*;
import net.neptech.service.FlowableService;
import net.neptech.util.FlowableUtil;
import net.neptech.util.JsonUtil;
import net.neptech.util.ModelUtil;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Attachment;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static net.neptech.enums.workflow.InstanceConstant.VariableKey.ENABLE_SKIP_EXPRESSION;
import static net.neptech.enums.workflow.InstanceConstant.VariableKey.FLOW_UNIQUE_ID;

/**
 * @Author Saya
 * @Date 2025/8/19 14:46
 * @Description flowable引擎核心服务
 **/
@Service
@Slf4j
@RequiredArgsConstructor
public class FlowableServiceImpl implements FlowableService {
    //flowable引擎提供的服务API
    //实例操作
    private final RuntimeService runtimeService;
    //用户任务操作（签收、完成等）
    private final TaskService taskService;
    //设定工作流
    private final RepositoryService repositoryService;
    //历史信息查询
    private final HistoryService historyService;

    /**
     * @Author Saya
     * @Date 2025/8/21 14:25
     * @Description 从dto对象创建工作流
     * @Params [createFlowDto]
     * @Return java.lang.String
     **/
    @Transactional
    @Override
    public String create(CreateFlowDto createFlowDto) {
        //拼接工作流ID
        String flowId = "p" + RandomUtil.randomString(6) + System.currentTimeMillis();
        BpmnModel bpmnModel = ModelUtil.buildBpmnModel(createFlowDto.getNode(), createFlowDto.getProcessName(), flowId);
        //这里生成BPMN流程文件保存在以下目录 文件保存可以替换为OSS，也可以不保存文件
        {
            byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
            String filename = "/tmp/flowable-deployment/" + flowId + ".bpmn20.xml";
            log.debug("部署时的模型文件：{}", filename);
            FileUtil.writeBytes(bpmnBytes, filename);
        }
        //根据提供的dto对象创建工作流并保存在flowable的数据库中
        repositoryService.createDeployment().addBpmnModel(StrUtil.format("{}.bpmn20.xml", flowId), bpmnModel).deploy();
        log.info("流程创建完成：flowId={}", flowId);
        return flowId;
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 14:26
     * @Description 根据dto对象发起一个工作流实例
     * @Params [flowInstanceParamDto]
     * @Return java.lang.String 工作流实例ID
     **/
    @Transactional
    @Override
    public String start(InstanceParamDto flowInstanceParamDto) {
        String flowId = flowInstanceParamDto.getFlowId();
        //这里省略了前置检查
        //设置当前流程的执行人
        Authentication.setAuthenticatedUserId(flowInstanceParamDto.getStartUserId());
        Map<String, Object> paramMap = flowInstanceParamDto.getParamMap();
        //支持自动跳过
        paramMap.put(ENABLE_SKIP_EXPRESSION, true);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowId, flowInstanceParamDto.getBizKey(), paramMap);
        return processInstance.getProcessInstanceId();
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 14:40
     * @Description 根据dto信息清理工作流数据
     * @Params [clearFlowParamDto]
     **/
    @Transactional
    @Override
    public void clearProcess(ClearFlowParamDto clearFlowParamDto) {
        List<String> flowIdList = clearFlowParamDto.getFlowIdList();
        String userName = clearFlowParamDto.getStaffName();
        String userId = clearFlowParamDto.getStaffId();

        //清理流程
        List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionKeys(CollUtil.newHashSet(flowIdList)).list();
        if (!processInstanceList.isEmpty()) {
            Set<String> processInstanceIdSet = processInstanceList.stream().map(Execution::getProcessInstanceId).collect(Collectors.toSet());
            runtimeService.bulkDeleteProcessInstances(processInstanceIdSet, StrUtil.format("[{}]({})清理流程", userName, userId));
        }
        //清理历史流程
        historyService.createHistoricProcessInstanceQuery().processDefinitionKeyIn(flowIdList).list().forEach(w -> historyService.deleteHistoricProcessInstance(w.getId()));
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 14:41
     * @Description 查询某用户的待办事项
     * @Params [taskQueryParamDto]
     * @Return net.neptech.dto.workflow.PageResult<net.neptech.dto.workflow.TaskDto>
     **/
    @Override
    public PageResultDto<TaskDto> queryTodoTask(TaskQueryParamDto taskQueryParamDto) {
        String assign = taskQueryParamDto.getAssign();
        //根据用户id查询待办清单
        TaskQuery taskQuery = taskService.createTaskQuery();
        List<Task> tasks = taskQuery.taskAssignee(assign).orderByTaskCreateTime().desc().listPage((taskQueryParamDto.getPageNum() - 1) * taskQueryParamDto.getPageSize(), taskQueryParamDto.getPageSize());
        long count = taskQuery.taskAssignee(assign).count();
        List<TaskDto> taskDtoList = new ArrayList<>();
        for (int i = 0; i < tasks.size(); i++) {
            Task task = tasks.get(i);
            String taskId = task.getId();
            String processInstanceId = task.getProcessInstanceId();
            log.debug((i + 1) + ") (" + taskId + ") " + task.getName() + " processInstanceId={} executionId={}", processInstanceId, task.getExecutionId());
            Map<String, Object> taskServiceVariables = taskService.getVariables(task.getId());
            log.debug("任务变量:{}", JSONUtil.toJsonStr(taskServiceVariables));
            //nodeId
            String taskDefinitionKey = task.getTaskDefinitionKey();

            String processDefinitionId = task.getProcessDefinitionId();
            //流程id
            String flowId = FlowableUtil.getFlowId(processDefinitionId);
            TaskDto taskDto = new TaskDto();
            taskDto.setFlowId(flowId);
            taskDto.setTaskCreateTime(task.getCreateTime());
            taskDto.setNodeId(taskDefinitionKey);
            taskDto.setParamMap(taskServiceVariables);
            taskDto.setProcessInstanceId(processInstanceId);
            taskDto.setTaskId(taskId);
            taskDto.setAssign(task.getAssignee());
            taskDto.setTaskName(task.getName());
            taskDtoList.add(taskDto);
        }
        PageResultDto<TaskDto> pageResultDto = new PageResultDto<>();
        pageResultDto.setTotal(count);
        pageResultDto.setRecords(taskDtoList);
        return pageResultDto;
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 14:48
     * @Description 查询用户已经处理的任务（单个步骤）
     * @Params [taskQueryParamDto]
     * @Return net.neptech.dto.workflow.PageResult<net.neptech.dto.workflow.TaskDto>
     **/
    @Override
    public PageResultDto<TaskDto> queryCompletedTask(TaskQueryParamDto taskQueryParamDto) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
        List<HistoricTaskInstance> list = historicTaskInstanceQuery.taskAssignee(taskQueryParamDto.getAssign()).taskWithoutDeleteReason().finished().orderByHistoricTaskInstanceEndTime().desc().listPage((taskQueryParamDto.getPageNum() - 1) * taskQueryParamDto.getPageSize(), taskQueryParamDto.getPageSize());
        long count = historicTaskInstanceQuery.taskAssignee(taskQueryParamDto.getAssign()).taskWithoutDeleteReason().finished().count();
        List<TaskDto> taskDtoList = new ArrayList<>();
        for (HistoricTaskInstance instance : list) {
            String activityId = instance.getTaskDefinitionKey();
            String activityName = instance.getName();
            String executionId = instance.getExecutionId();
            String taskId = instance.getId();
            Date startTime = instance.getStartTime();
            Date endTime = instance.getEndTime();
            Long durationInMillis = instance.getDurationInMillis();
            String processInstanceId = instance.getProcessInstanceId();
            String processDefinitionId = instance.getProcessDefinitionId();
            //流程id
            String flowId = FlowableUtil.getFlowId(processDefinitionId);
            TaskDto taskDto = new TaskDto();
            taskDto.setFlowId(flowId);
            taskDto.setTaskCreateTime(startTime);
            taskDto.setTaskEndTime(endTime);
            taskDto.setNodeId(activityId);
            taskDto.setExecutionId(executionId);
            taskDto.setProcessInstanceId(processInstanceId);
            taskDto.setDurationInMillis(durationInMillis);
            taskDto.setTaskId(taskId);
            taskDto.setAssign(instance.getAssignee());
            taskDto.setTaskName(activityName);
            taskDtoList.add(taskDto);
        }
        PageResultDto<TaskDto> pageResultDto = new PageResultDto<>();
        pageResultDto.setTotal(count);
        pageResultDto.setRecords(taskDtoList);
        return pageResultDto;
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 14:49
     * @Description 查询用户已经办理的流程实例（整条工作流）
     * @Params [processQueryParamDto]
     * @Return net.neptech.dto.workflow.PageResult<net.neptech.dto.workflow.InstanceDto>
     **/
    @Override
    public PageResultDto<InstanceDto> queryCompletedInstance(QueryParamDto processQueryParamDto) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
        if (!processQueryParamDto.getFlowIdList().isEmpty()) {
            historicProcessInstanceQuery = historicProcessInstanceQuery.processDefinitionKeyIn(processQueryParamDto.getFlowIdList());
        }
        List<HistoricProcessInstance> list = historicProcessInstanceQuery.involvedUser(processQueryParamDto.getAssign().toString()).orderByProcessInstanceStartTime().desc().listPage((processQueryParamDto.getPageNum() - 1) * processQueryParamDto.getPageSize(), processQueryParamDto.getPageSize());
        long count = historicProcessInstanceQuery.involvedUser(processQueryParamDto.getAssign().toString()).count();
        List<InstanceDto> flowInstanceParamDtoList = new ArrayList<>();
        for (HistoricProcessInstance historicProcessInstance : list) {
            HistoricProcessInstanceEntityImpl historicProcessInstanceEntity = (HistoricProcessInstanceEntityImpl) historicProcessInstance;
            String processInstanceId = historicProcessInstanceEntity.getProcessInstanceId();
            String flowId = historicProcessInstanceEntity.getProcessDefinitionKey();
            String processName = historicProcessInstanceEntity.getProcessDefinitionName();
            InstanceDto instanceDto = new InstanceDto();
            instanceDto.setInstanceId(processInstanceId);
            instanceDto.setFlowId(flowId);
            instanceDto.setName(processName);
            instanceDto.setStartUserId(historicProcessInstance.getStartUserId());
            instanceDto.setStartTime(historicProcessInstance.getStartTime());
            instanceDto.setEndTime(historicProcessInstance.getEndTime());
            flowInstanceParamDtoList.add(instanceDto);
        }
        PageResultDto<InstanceDto> pageResultDto = new PageResultDto<>();
        pageResultDto.setTotal(count);
        pageResultDto.setRecords(flowInstanceParamDtoList);
        return pageResultDto;
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 14:58
     * @Description 完成任务
     * @Params [taskParamDto]
     **/
    @Transactional
    @Override
    public void complete(TaskParamDto taskParamDto) {
        Task task = taskService.createTaskQuery().taskId(taskParamDto.getTaskId()).singleResult();
        if (task == null) throw new RuntimeException("任务不存在");
        boolean approveResult = taskParamDto.getApproveResult();
        runtimeService.setVariableLocal(task.getExecutionId(), InstanceConstant.VariableKey.APPROVE_RESULT, approveResult);
        //非自动完成
        runtimeService.setVariableLocal(task.getExecutionId(), InstanceConstant.VariableKey.AUTO_COMPLETE_TASK, false);
        //保存任务类型
        taskService.setVariableLocal(task.getId(), InstanceConstant.VariableKey.TASK_TYPE, approveResult ? TaskTypeEnum.PASS.getValue() : TaskTypeEnum.REFUSE.getValue());
        //保存变量
        if (approveResult) {
            taskService.setVariableLocal(task.getId(), InstanceConstant.VariableKey.TASK_VARIABLES, taskParamDto.getParamMap());
        }
        String descType = approveResult ? ApproveDescTypeEnum.PASS.getType() : ApproveDescTypeEnum.REFUSE.getType();
        String commentId;
        if (StrUtil.isNotBlank(taskParamDto.getApproveDesc())) {
            Comment comment = saveUserCommentToTask(descType, taskParamDto.getApproveDesc(), taskParamDto.getUserId(), task.getId(), task.getProcessInstanceId());
            commentId = comment.getId();
        } else {
            Comment comment = saveSysCommentToTask(descType, taskParamDto.getUserId(), task.getId(), task.getProcessInstanceId());
            commentId = comment.getId();
        }
        //保存图片和文件
        saveAttachment(taskParamDto, commentId, task.getId(), task.getProcessInstanceId());
        //通过才设置变量
        if (approveResult) {
            Map<String, Object> paramMap = taskParamDto.getParamMap();
            taskService.complete(task.getId(), paramMap);
        } else {
            taskService.complete(task.getId());
        }
    }


    /**
     * @Author Saya
     * @Date 2025/8/21 15:13
     * @Description 存储任务附件
     * @Params [taskParamDto, commentId, taskId, processInstanceId]
     * @Return void
     **/
    private void saveAttachment(TaskParamDto taskParamDto, String commentId, String taskId, String processInstanceId) {
        log.info("保存附件的任务id：{}", taskId);
        List<UploadValue> approveImageList = taskParamDto.getApproveImageList();
        List<UploadValue> approveFileList = taskParamDto.getApproveFileList();
        if (CollUtil.isNotEmpty(approveImageList)) {
            for (UploadValue uploadValue : approveImageList) {
                taskService.createAttachment(ApproveAttachmentTypeEnum.IMAGE.getType(), taskId, processInstanceId, uploadValue.getName(), commentId, uploadValue.getUrl());
            }
        }
        if (CollUtil.isNotEmpty(approveFileList)) {
            for (UploadValue uploadValue : approveFileList) {
                taskService.createAttachment(ApproveAttachmentTypeEnum.FILE.getType(), taskId, processInstanceId, uploadValue.getName(), commentId, uploadValue.getUrl());
            }
        }
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 15:17
     * @Description 存储任务评论
     * @Params [type, desc, userId, descTitle, taskId, processInstanceId]
     * @Return org.flowable.engine.task.Comment
     **/
    private Comment saveUserCommentToTask(String type, String desc, String userId, String taskId, String processInstanceId) {
        TaskCommentDto taskCommentDto = TaskCommentDto.builder().content(desc).title("提交任务并添加了评论").sys(false).userId(userId).build();
        return taskService.addComment(taskId, processInstanceId, type, JsonUtil.toJSONString(taskCommentDto));
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 15:19
     * @Description 存储系统评论
     * @Params [type, desc, userId, taskId, processInstanceId]
     * @Return org.flowable.engine.task.Comment
     **/
    private Comment saveSysCommentToTask(String type, String userId, String taskId, String processInstanceId) {
        TaskCommentDto taskCommentDto = TaskCommentDto.builder().content("提交任务").sys(true).userId(userId).build();
        return taskService.addComment(taskId, processInstanceId, type, JsonUtil.toJSONString(taskCommentDto));
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 15:20
     * @Description 查询任务
     * @Params [taskId, staffId]
     * @Return net.neptech.dto.workflow.TaskResultDto
     **/
    @Override
    public TaskResultDto queryTask(String taskId, Long staffId) {
        DelegationState delegationState = null;
        //实例id
        String processInstanceId;
        Object delegateVariable = false;
        String processDefinitionId;
        //nodeId
        String taskDefinitionKey;
        String executionId;
        String flowUniqueId;
        String assignee;
        String nodeName;
        boolean taskExist = true;
        {
            TaskQuery taskQuery = taskService.createTaskQuery();
            Task task = taskQuery.taskId(taskId).singleResult();
            if (task == null) {
                HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
                if (historicTaskInstance == null) {
                    throw new RuntimeException("任务不存在");
                }
                taskExist = false;
                taskDefinitionKey = historicTaskInstance.getTaskDefinitionKey();
                nodeName = historicTaskInstance.getName();
                processInstanceId = historicTaskInstance.getProcessInstanceId();
                executionId = historicTaskInstance.getExecutionId();
                assignee = historicTaskInstance.getAssignee();
                processDefinitionId = historicTaskInstance.getProcessDefinitionId();
                HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).taskId(taskId).variableName(FLOW_UNIQUE_ID).singleResult();
                flowUniqueId = historicVariableInstance == null ? null : Convert.toStr(historicVariableInstance.getValue());
            } else {
                processDefinitionId = task.getProcessDefinitionId();
                taskDefinitionKey = task.getTaskDefinitionKey();
                delegationState = task.getDelegationState();
                processInstanceId = task.getProcessInstanceId();
                executionId = task.getExecutionId();
                nodeName = task.getName();
                assignee = task.getAssignee();
                delegateVariable = taskService.getVariableLocal(taskId, "delegate");
                flowUniqueId = taskService.getVariable(taskId, FLOW_UNIQUE_ID, String.class);
            }
        }
        //流程id
        String flowId = FlowableUtil.getFlowId(processDefinitionId);
        Map<String, Object> variableAll = new HashMap<>();
        //表单处理
        if (taskExist) {
            Map<String, Object> variables = taskService.getVariables(taskId);
            variableAll.putAll(variables);
        }
        TaskResultDto taskResultDto = new TaskResultDto();
        taskResultDto.setFlowId(flowId);
        taskResultDto.setUserId(assignee);
        taskResultDto.setNodeId(taskDefinitionKey);
        taskResultDto.setNodeName(nodeName);
        taskResultDto.setCurrentTask(taskExist && staffId.toString().equals(assignee));
        taskResultDto.setExecutionId(executionId);
        taskResultDto.setDelegate(Convert.toBool(delegateVariable, false));
        taskResultDto.setVariableAll(variableAll);
        taskResultDto.setProcessInstanceId(processInstanceId);
        taskResultDto.setFrontJoinTask(delegationState != null && StrUtil.equals(delegationState.toString(), InstanceConstant.VariableKey.PENDING));
        taskResultDto.setFlowUniqueId(flowUniqueId);
        return taskResultDto;
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 15:26
     * @Description 查询任务评论
     * @Params [paramDto]
     * @Return java.util.List<net.neptech.dto.workflow.SimpleApproveDescDto>
     **/
    @Override
    public List<SimpleApproveDescDto> queryTaskComments(VariableQueryParamDto paramDto) {
        String taskId = paramDto.getTaskId();
        List<Comment> taskComments = new ArrayList<>();
        for (String s : ApproveDescTypeEnum.getTypeList()) {
            List<Comment> approveDescList = taskService.getTaskComments(taskId, s);
            taskComments.addAll(approveDescList);
        }
        //查询所有的附件
        List<Attachment> taskAttachments = taskService.getTaskAttachments(taskId);
        List<SimpleApproveDescDto> simpleApproveDescDtoList = new ArrayList<>();
        for (Comment comment : taskComments) {
            String id = comment.getId();
            Date time = comment.getTime();
            String fullMessage = comment.getFullMessage();
            TaskCommentDto taskCommentDto = JsonUtil.parseObject(fullMessage, TaskCommentDto.class);
            String userId = null;
            if (taskCommentDto != null) {
                userId = taskCommentDto.getUserId();
            }
            Boolean isSys = null;
            if (taskCommentDto != null) {
                isSys = taskCommentDto.getSys();
            }
            SimpleApproveDescDto simpleApproveDescDto = new SimpleApproveDescDto();
            simpleApproveDescDto.setDate(time);
            simpleApproveDescDto.setMsgId(id);
            simpleApproveDescDto.setSys(isSys);
            simpleApproveDescDto.setUserId(userId);
            simpleApproveDescDto.setType(comment.getType());
            simpleApproveDescDto.setMessage(fullMessage);
            //图片文件
            {
                List<Attachment> collect = taskAttachments.stream().filter(w -> StrUtil.equals(w.getDescription(), id)).filter(w -> StrUtil.equals(w.getType(), ApproveAttachmentTypeEnum.IMAGE.getType())).toList();
                List<UploadValue> approveImageList = new ArrayList<>();
                for (Attachment attachment : collect) {
                    UploadValue uploadValue = new UploadValue();
                    uploadValue.setUrl(attachment.getUrl());
                    uploadValue.setName(attachment.getName());
                    approveImageList.add(uploadValue);
                }
                simpleApproveDescDto.setApproveImageList(approveImageList);
            }
            {
                List<Attachment> collect = taskAttachments.stream().filter(w -> StrUtil.equals(w.getDescription(), id)).filter(w -> StrUtil.equals(w.getType(), ApproveAttachmentTypeEnum.FILE.getType())).toList();
                List<UploadValue> approveImageList = new ArrayList<>();
                for (Attachment attachment : collect) {
                    UploadValue uploadValue = new UploadValue();
                    uploadValue.setUrl(attachment.getUrl());
                    uploadValue.setName(attachment.getName());
                    approveImageList.add(uploadValue);
                }
                simpleApproveDescDto.setApproveFileList(approveImageList);
            }
            simpleApproveDescDtoList.add(simpleApproveDescDto);
        }
        return simpleApproveDescDtoList;
    }

    /**
     * @Author Saya
     * @Date 2025/8/21 15:28
     * @Description 查询任务的执行人
     * @Params [taskParamDto]
     * @Return java.util.List<net.neptech.dto.workflow.TaskDto>
     **/
    @Override
    public List<TaskDto> queryTaskAssignee(TaskParamDto taskParamDto) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        if (StrUtil.isNotBlank(taskParamDto.getNodeId())) {
            taskQuery = taskQuery.taskDefinitionKey(taskParamDto.getNodeId());
        }
        List<Task> list = taskQuery.processInstanceId(taskParamDto.getProcessInstanceId()).list();
        List<TaskDto> taskDtoList = new ArrayList<>();
        for (Task task : list) {
            TaskDto taskDto = new TaskDto();
            taskDto.setAssign(task.getAssignee());
            taskDto.setExecutionId(task.getExecutionId());
            taskDto.setTaskId(task.getId());
            taskDto.setTaskName(task.getName());
            taskDto.setNodeId(task.getTaskDefinitionKey());
            taskDto.setProcessInstanceId(task.getProcessInstanceId());
            String processDefinitionId = task.getProcessDefinitionId();
            //流程id
            String flowId = FlowableUtil.getFlowId(processDefinitionId);
            taskDto.setFlowId(flowId);
            taskDtoList.add(taskDto);
        }
        return taskDtoList;
    }

    /**
     * 删除流程
     */
    @Override
    public void delete(InstanceParamDto processInstanceParamDto) {

        List<String> processInstanceIdList = processInstanceParamDto.getProcessInstanceIdList();
        for (String processInstanceId : processInstanceIdList) {
            if (runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).count() > 0) {
                runtimeService.deleteProcessInstance(processInstanceId, processInstanceParamDto.getReason());
            }
        }
    }

    /**
     * 查询统计数据
     */
    @Override
    public IndexPageStatistics querySimpleData(String userId) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        //待办数量
        long pendingNum = taskQuery.taskAssignee((userId)).count();
        //已完成任务
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        long completedNum = historicActivityInstanceQuery.taskAssignee(String.valueOf(userId)).finished().count();
        return IndexPageStatistics.builder().pendingNum(pendingNum).completedNum(completedNum).build();
    }

    /**
     * 查询变量
     */
    @Override
    public Map<String, Object> queryVariables(VariableQueryParamDto paramDto) {
        long count = runtimeService.createProcessInstanceQuery().processInstanceId(paramDto.getExecutionId()).count();
        if (count > 0) {
            return runtimeService.getVariables(paramDto.getExecutionId());
        }
        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(paramDto.getExecutionId()).list();

        Map<String, Object> variables = new HashMap<>();
        for (HistoricVariableInstance historicVariableInstance : list) {
            variables.put(historicVariableInstance.getVariableName(), historicVariableInstance.getValue());
        }
        return variables;
    }
}
